package com.tamartech.greendb.loader;

import java.io.PrintWriter;
import java.util.Date;

import org.apache.log4j.Logger;

import com.tamartech.greendb.dao.ElectoralRollDAO;
import com.tamartech.greendb.dao.ElectoralRollEntryDAO;
import com.tamartech.greendb.dao.WardDAO;
import com.tamartech.greendb.data.Address;
import com.tamartech.greendb.data.ElectoralRoll;
import com.tamartech.greendb.data.ElectoralRollEntry;
import com.tamartech.greendb.data.Person;
import com.tamartech.greendb.data.Ward;

public class ElectoralRollLoader
{
    private static Logger log = Logger.getLogger (ElectoralRollLoader.class);

    private ElectoralRoll roll = null;
    private ElectoralRollEntry rollEntry = null;

    private String firstNames;
    private String surname;
    
    String[] addressLines = null;
    String postcode = null;
    
    private Date date18th;
    
    PrintWriter newPersonLog;
    PrintWriter newAddressLog;
    
    public ElectoralRollLoader (PrintWriter newPersonLog, PrintWriter newAddressLog)
    {
        this.newPersonLog = newPersonLog;
        this.newAddressLog = newAddressLog;
    }
    
    public void begin (String wardName, Date rollDate) throws Exception
    {
        // check we haven't previously loaded this roll
        WardDAO wDAO = new WardDAO();
        Ward w = wDAO.get(wardName);
        
        if (w == null)
            throw new Exception ("Ward " + wardName + " not found");
        
        ElectoralRollDAO erDAO = new ElectoralRollDAO();
        
        if (erDAO.getByDate(w, rollDate) != null)
            throw new Exception ("Electoral roll for ward: " + wardName + ". date: " + rollDate + " already loaded");
        
        roll = new ElectoralRoll();
        roll.setWard(w);
        roll.setDate(rollDate);
        
        erDAO.save(roll);
    }
    
    public void end()
    {
        
    }
    
    public void beginEntry (String pollingDistrict, int voterNumber, Integer voterNumberSuffix)
    {
        firstNames = null;
        surname = null;
        addressLines = null;
        date18th = null;

        rollEntry = new ElectoralRollEntry();
        
        rollEntry.setElectoralRoll(roll);
        rollEntry.setPollingDistrict(pollingDistrict);
        rollEntry.setVoterNumber(voterNumber);
        if (voterNumberSuffix != null)
            rollEntry.setVoterNumberSuffix(voterNumberSuffix);
    }
    
    public void endEntry()
    {
        // check we have a full name
        if (firstNames == null || surname == null)
            logError("Name incomplete");
        else
        if (addressLines == null)
            logError ("Missing address");
        else
        {
            try
            {
                Person p = new Person();
                
                p.setSurname(surname);
                p.setFirstNames(firstNames);
                if (date18th != null)
                    p.setBirthday18(date18th);
                
                Address a = createAddress (addressLines, postcode);
                
                PersonMatcher matcher = new PersonMatcher (p, a, roll);
                
                p = matcher.getPerson();
                a = matcher.getAddress();
                
                if (matcher.isNewAddress())
                    newAddressLog.println (a.toString());
                if (matcher.isNewPerson())
                    newPersonLog.println (p.toString() + " -- " + a.toString());
                
                rollEntry.setPerson(p);
                rollEntry.setAddress(a);
                
                ElectoralRollEntryDAO ereDAO = new ElectoralRollEntryDAO();
                ereDAO.save(rollEntry);
            }
            catch (Exception e)
            {
                logError ("Exception thrown", e);
            }
         }
        
    }
    
    private static Address createAddress (String[] addressLines, String postcode)
    {
        // the postcode in the address columns is coming through with garbage chars in it
        // quickest fix seems to be to replace it with the one from the postcode column
        Address address = new Address();
        
        // reverse through the address to find the last populated line. That will be the postcode
        
        int postcodeIndex = addressLines.length - 1;
        
        for (;;)
        {
            if (postcodeIndex < 0 || addressLines[postcodeIndex].length() > 0)
                break;
                
            postcodeIndex--;
        }
        
        if (postcodeIndex >= 0)
        {
//            address.setPostcode (addressLines[postcodeIndex]);
            address.setPostcode (postcode);
            
            if (postcodeIndex > 0)
                address.setAddress1(addressLines[0]);
            if (postcodeIndex > 1)
                address.setAddress2(addressLines[1]);
            if (postcodeIndex > 2)
                address.setAddress3(addressLines[2]);
            if (postcodeIndex > 3)
                address.setAddress4(addressLines[3]);
            if (postcodeIndex > 4)
                address.setAddress5(addressLines[4]);           
        }
        
//        for (int i = 0; i < address.getPostcode().length(); i++)
//        {   
//            char ch = address.getPostcode().charAt(i);
//            log.info("postcode char: [" + ch + "]. code: " + Character.getNumericValue(ch));
//        }
        
        return address;
    }
    
    private void logError (String text)
    {
        logError (text, null);
    }
    
    private void logError (String text, Throwable exception)
    {
        String message = "Ref: " + rollEntry.getPollingDistrict() + " " + rollEntry.getVoterNumber() + 
                         (rollEntry.getVoterNumberSuffix() == null ? "" : "/" + rollEntry.getVoterNumberSuffix()) +
                         ". Text: " + text;
        
        if (exception == null)
            log.error(message);
        else
            log.error(message, exception);
    }
    
    public void putName (String firstNames, String surname)
    {
        this.firstNames = firstNames;
        this.surname = surname;
    }
    
    public void putAddress (String address1,
                            String address2,
                            String address3,
                            String address4,
                            String address5,
                            String address6,
                            String postcode)
    {
        this.addressLines = new String [6];
        
        this.addressLines[0] = address1;
        this.addressLines[1] = address2;
        this.addressLines[2] = address3;
        this.addressLines[3] = address4;
        this.addressLines[4] = address5;
        this.addressLines[5] = address6;
        
        this.postcode = postcode;
    }
    
    public void put18thBirthday (Date date)
    {
        this.date18th = date;
    }
    
    public void putVoteType (String voteType)
    {
        if (voteType.length() > 0)
            rollEntry.setVoteType(voteType);
    }
}
